﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.CodeDom;
using OpenComposite.EII.Repository;
using System.Runtime.Serialization;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.ServiceModel;
using System.Xml;
using System.Workflow.Activities;
using System.Workflow.Runtime;
using System.Reflection;
using OpenComposite.EII.Designer.Workflow;
using System.Collections.ObjectModel;
using System.Workflow.ComponentModel.Compiler;
using System.Configuration;
using System.Web.Configuration;
using OpenComposite.Base.Collections;
using OpenComposite.Base.Structures;
using OpenComposite.Forms;

namespace OpenComposite.EII.CodeGenerators
{
	internal class CompositeDeployment
	{
		#region Initialization
		public CompositeDeployment(IServiceProvider serviceProvider)
		{
			_serviceProvider = serviceProvider;
		}
		#endregion

		#region Internal Members

		#region Properties
		public string Namespace
		{
			get { return _compositeNamespace; }
		}
		public string NamespaceData
		{
			get { return _compositeDataNamespace; }
		}
		public string NamespaceRules
		{
			get { return null; }
		}

		#endregion

		#region Methods
		internal void DeployComposite(ServiceModule composite, string targetPath, bool update, bool generateStub)
		{
			// validate arguments
			if ( composite == null ) {
				throw new ArgumentNullException("composite");
			}
			if ( composite.Capability == null && composite.GetVerbs().Count == 0 ) {
				throw new NullReferenceException(string.Format(
					"The composite \"{0}\" was not assigned to a capability.", composite.Name));
			}
			if ( string.IsNullOrEmpty(targetPath) ) {
				throw new ArgumentException("The target path is null oder empty.");
			}
			OpenComposite.Base.WaitMouse waitmouse = new OpenComposite.Base.WaitMouse();
			try {

				TypeProvider typeProvider = createTypeProvider(_serviceProvider);
				// set source directory
				string sourcepath = Path.Combine(Application.StartupPath, @"Templates\Orchestration");
				// set and create target directory
				string targetpath = ( targetPath.EndsWith(composite.Name) ? targetPath : Path.Combine(targetPath, composite.Name) );
				if ( !Directory.Exists(targetpath) ) Directory.CreateDirectory(targetpath);

				// set member variables
				_sourcePath = sourcepath;
				_targetPath = targetpath;

				_update = update;
				_override = !update;

				_composite = composite;

				_compositeNamespace = "OpenComposite.Composite." + composite.Name;
				_compositeDataNamespace = _compositeNamespace + ".Data";
				_compositeXMLNS = "http://www.OpenComposite.com/composite";

				if ( _composite.ExtendedProperties.BuildType == WorkflowBuildType.ASMX_IIS ) {
					this.deployWCFService(typeProvider, sourcepath, targetpath, composite, update, generateStub);
				} else {
					this.deployWCFService(typeProvider, sourcepath, targetpath, composite, update, generateStub);
				}

				// open project
				System.Diagnostics.Process.Start(targetpath);
			} catch ( Exception ex ) {
				MessageBox.Show(
					string.Format("The deployment of the composite failed.{0}{0}{1}",
								  Environment.NewLine, ex.Message),
					"Deploy Composite", MessageBoxButtons.OK, MessageBoxIcon.Error);
			} finally {
				try { waitmouse.Dispose(); } catch { }
				waitmouse = null;
			}
			//#endif
		}

		#endregion

		#endregion

		#region Private Members

		#region Variables

		private string _sourcePath;
		private string _targetPath;
		private string _compositeNamespace;
		private string _compositeDataNamespace;
		private string _compositeXMLNS;

		private ServiceModule _composite;
		private bool _update;
		private bool _override;

		private CodeMemberField _wfRuntime = null;

		private IServiceProvider _serviceProvider;

		#endregion

		#region Constants
		private const string cSetupWFEnvironment = "setupWFEnvironment";
		private const string cLocalService = "_localService";
		private const string cWorkflowRuntime = "_workflowRuntime";

		private static readonly string cNL = Environment.NewLine;
		private static readonly string CodeMethodworkflow_ReplyEvent =
			"\t\t\tThreadPool.QueueUserWorkItem(" + Environment.NewLine +
			"\t\t\t\tdelegate" + Environment.NewLine +
			"\t\t\t\t{" + Environment.NewLine +
			"\t\t\t\t\tif ( %DICT_CLIENTS%.ContainsKey(e.InstanceId) ) {" + Environment.NewLine +
			"\t\t\t\t\t\tI%WF_NAME%Callback callback;" + Environment.NewLine +
			"\t\t\t\t\t\tif ( %DICT_CLIENTS%.TryGetValue(e.InstanceId, out callback) )" + Environment.NewLine +
			"\t\t\t\t\t\t\t%WF_METHODCALLBACK_CALL%" + Environment.NewLine +
			"\t\t\t\t\t}" + Environment.NewLine +
			"\t\t\t\t}" + Environment.NewLine +
			"\t\t\t);";

		private static readonly string cSolutionBase =
			"Microsoft Visual Studio Solution File, Format Version 10.00" + cNL +
			"# Visual Studio 2008" + cNL +
			"{0}" +
			"Global" + cNL +
			"\tGlobalSection(SolutionConfigurationPlatforms) = preSolution" + cNL +
			"\t\tDebug|.NET = Debug|.NET" + cNL +
			"\t\tDebug|Any CPU = Debug|Any CPU" + cNL +
			"\t\tDebug|Mixed Platforms = Debug|Mixed Platforms" + cNL +
			"\t\tRelease|.NET = Release|.NET" + cNL +
			"\t\tRelease|Any CPU = Release|Any CPU" + cNL +
			"\t\tRelease|Mixed Platforms = Release|Mixed Platforms" + cNL +
			"\tEndGlobalSection" + cNL +
			"\tGlobalSection(ProjectConfigurationPlatforms) = postSolution" + cNL +
			"{1}" +
			"\tEndGlobalSection" + cNL +
			"\tGlobalSection(SolutionProperties) = preSolution" + cNL +
			"\t\tHideSolutionNode = FALSE" + cNL +
			"\tEndGlobalSection" + cNL +
			"EndGlobal" + cNL;
		private static readonly string cSolutionProject =
			"Project(\"{{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}}\") = \"{0}\", \"{1}\", " +
			"\"{2}\"" + cNL +
			"EndProject" + cNL;
		private static readonly string cSolutionWebService =
			"Project(\"{{E24C65DC-7377-472B-9ABA-BC803B73C61A}}\") = \"WCFService\", \"WCFService\", " +
			"\"{0}\"" + cNL +
			"\tProjectSection(WebsiteProperties) = preProject" + cNL +
			"\t\tTargetFramework = \"3.0\"" + cNL +
			"\t\tProjectReferences = \"{1}\"" + cNL +
			"\t\tDebug.AspNetCompiler.VirtualPath = \"/WCFService\"" + cNL +
			"\t\tDebug.AspNetCompiler.PhysicalPath = \"WCFService\\\"" + cNL +
			"\t\tDebug.AspNetCompiler.TargetPath = \"PrecompiledWeb\\WCFService\\\"" + cNL +
			"\t\tDebug.AspNetCompiler.Updateable = \"true\"" + cNL +
			"\t\tDebug.AspNetCompiler.ForceOverwrite = \"true\"" + cNL +
			"\t\tDebug.AspNetCompiler.FixedNames = \"false\"" + cNL +
			"\t\tDebug.AspNetCompiler.Debug = \"True\"" + cNL +
			"\t\tRelease.AspNetCompiler.VirtualPath = \"/WCFService\"" + cNL +
			"\t\tRelease.AspNetCompiler.PhysicalPath = \"WCFService\\\"" + cNL +
			"\t\tRelease.AspNetCompiler.TargetPath = \"PrecompiledWeb\\WCFService\\\"" + cNL +
			"\t\tRelease.AspNetCompiler.Updateable = \"true\"" + cNL +
			"\t\tRelease.AspNetCompiler.ForceOverwrite = \"true\"" + cNL +
			"\t\tRelease.AspNetCompiler.FixedNames = \"false\"" + cNL +
			"\t\tRelease.AspNetCompiler.Debug = \"False\"" + cNL +
			"\t\tVWDPort = \"2046\"" + cNL +
			"\tEndProjectSection" + cNL +
			"EndProject" + cNL;
		private static readonly string cSolutionPrjBuildConfig =
			"\t\t{0}.Debug|.NET.ActiveCfg = Debug|Any CPU" + cNL +
			"\t\t{0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU" + cNL +
			//"\t\t{0}.Debug|Any CPU.Build.0 = Debug|Any CPU" + cNL +
			"\t\t{0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU" + cNL +
			"\t\t{0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU" + cNL +
			"\t\t{0}.Release|.NET.ActiveCfg = Release|Any CPU" + cNL +
			"\t\t{0}.Release|Any CPU.ActiveCfg = Release|Any CPU" + cNL +
			//"\t\t{0}.Release|Any CPU.Build.0 = Release|Any CPU" + cNL +
			"\t\t{0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU" + cNL;// +
		//"\t\t{0}.Release|Mixed Platforms.Build.0 = Release|Any CPU" + cNL;

		#endregion

		#region Methods
		private void deployWCFService(TypeProvider typeProvider,
									  string sourcePath, string targetPath,
									  ServiceModule composite, bool update, bool generateStub)
		{
			string targetPathWCFService = Path.Combine(targetPath, "WCFService");
			List<Repository.Workflow> workflows;

			// create wcf service
			this.createWCFService(typeProvider, sourcePath, targetPathWCFService, composite, update, out workflows, generateStub);

			// add required dlls to Bin folder
			// copy OpenComposite.Shared.dll
			File.Copy(
				Path.Combine(Application.StartupPath, "OpenComposite.Shared.dll"),
				Path.Combine(targetPathWCFService, "Bin\\OpenComposite.Shared.dll"),
				true);

			// create composite solution file
			createSolutionFile(composite, workflows);

		}

		private void createWCFService(TypeProvider typeProvider,
			string sourcePath, string targetPathWCFService,
			ServiceModule composite, bool update, out List<Repository.Workflow> workflows, bool generateStub)
		{
			CodeCompileUnit ccuIService;
			CodeCompileUnit ccuService;
			CodeCompileUnit ccuData;
			CodeCompileUnit ccuMapping;
			CodeCompileUnit ccuContracts;
			CodeCompileUnit ccuRules;

			List<XmlDocument> configs;
			bool hasWorkflow;
			string compositeidentifier = RepositoryService.GetIdentifier(composite.Name);

			// create folder structure
			string pathAppCode = Path.Combine(targetPathWCFService, "App_Code");
			string pathBin = Path.Combine(targetPathWCFService, "Bin");

			if ( !Directory.Exists(pathAppCode) ) Directory.CreateDirectory(pathAppCode);
			if ( !Directory.Exists(pathBin) ) Directory.CreateDirectory(pathBin);

			// TODO: initialize rules
			ccuRules = new CodeCompileUnit();

			// create IService.cs and Data.cs
			createWCFIServiceAndDataCode(typeProvider, composite, out ccuIService, out ccuData,
				out hasWorkflow, out configs, out workflows);

			// create Web.config
			createWebConfig(sourcePath, targetPathWCFService, configs, hasWorkflow, compositeidentifier);

			// create Service.cs
			createWCFServiceCode(typeProvider, targetPathWCFService, composite,
				out ccuService, ccuIService, ccuData,
				out ccuMapping, out ccuContracts, ccuRules, generateStub);

			// save IService.cs, Service.cs, Data.cs to App_Code
			string data = CSharpGenerator.GenerateCodeString(ccuData);
			string iservice = CSharpGenerator.GenerateCodeString(ccuIService);
			string service = CSharpGenerator.GenerateCodeString(ccuService);
			string mapping = CSharpGenerator.GenerateCodeString(ccuMapping);
			string contracts = CSharpGenerator.GenerateCodeString(ccuContracts);

			File.WriteAllText(Path.Combine(pathAppCode, "Data.cs"), data);
			File.WriteAllText(Path.Combine(pathAppCode, "IService.cs"), iservice);
			File.WriteAllText(Path.Combine(pathAppCode, "Service.cs"), service);
			File.WriteAllText(Path.Combine(pathAppCode, "Mapping.cs"), mapping);
			File.WriteAllText(Path.Combine(pathAppCode, "Contracts.cs"), contracts);

			createSVCFile(sourcePath, targetPathWCFService, hasWorkflow, compositeidentifier);

		}

		private void createSVCFile(string sourcePath, string targetPathWCFService, bool hasWorkflow, string compositeidentifier)
		{
			// write svc file
			if ( hasWorkflow ) {
				// copy svc file for workflows
				string svcfile = File.ReadAllText(Path.Combine(sourcePath, "WCF_IIS\\WCFService\\Service.svc_"));
				svcfile = svcfile
					.Replace("%SERVICENAME%", _compositeNamespace + "." + compositeidentifier);
				File.WriteAllText(Path.Combine(targetPathWCFService, "Service.svc"), svcfile);
			} else {
				// copy standard svc file
				string svcfile = File.ReadAllText(Path.Combine(sourcePath, "Generic\\Service.svc_"));
				svcfile = svcfile
					.Replace("%SERVICENAME%", _compositeNamespace + "." + compositeidentifier);
				File.WriteAllText(Path.Combine(targetPathWCFService, "Service.svc"), svcfile);
			}

		}

		private void createWebConfig(string sourcePath, string targetPathWCFService, List<XmlDocument> configs, bool hasWorkflow, string compositeidentifier)
		{
			// write web.config
			if ( hasWorkflow ) {
				// copy web config file for workflows
				string webconfig = File.ReadAllText(Path.Combine(sourcePath, "WCF_IIS\\WCFService\\Web.config_"));
				webconfig = webconfig
					.Replace("%SERVICE_FULLNAME%", _compositeNamespace + "." + compositeidentifier)
					.Replace("%SERVICE_NAME%", compositeidentifier)
					.Replace("%INTERFACE_FULLNAME%", _compositeNamespace + ".I" + compositeidentifier)
					.Replace("%NAMESPACE%", _compositeXMLNS);
				File.WriteAllText(Path.Combine(targetPathWCFService, "Web.config"), webconfig);
				// add workflow configurations to web config
				XmlDocument xdTarget = new XmlDocument();
				xdTarget.Load(Path.Combine(targetPathWCFService, "Web.config"));
				XmlNode xnTargetServiceModel = xdTarget.SelectSingleNode("//system.serviceModel");
				XmlNode xnTargetBindungs = xnTargetServiceModel["bindings"];
				XmlNode xnTargetClient = xnTargetServiceModel["client"];
				if ( xnTargetBindungs == null ) {
					xnTargetBindungs = xnTargetServiceModel.AppendChild(xdTarget.CreateElement("bindings"));
				}
				if ( xnTargetClient == null ) {
					xnTargetClient = xnTargetServiceModel.AppendChild(xdTarget.CreateElement("client"));
				}
				foreach ( XmlDocument xdSource in configs ) {
					XmlNode xnSourceBindungs = xdSource.SelectSingleNode("//system.serviceModel/bindings");
					XmlNode xnSourceClient = xdSource.SelectSingleNode("//system.serviceModel/client");
					if ( xnSourceBindungs != null ) {
						foreach ( XmlNode xnSBC in xnSourceBindungs.ChildNodes ) {
							xnTargetBindungs.AppendChild(xdTarget.ImportNode(xnSBC, true));
						}
					}
					if ( xnSourceClient != null ) {
						foreach ( XmlNode xnSCC in xnSourceClient.ChildNodes ) {
							xnTargetClient.AppendChild(xdTarget.ImportNode(xnSCC, true));
						}
					}
				}
				xdTarget.Save(Path.Combine(targetPathWCFService, "Web.config"));
			} else {
				// copy standard web config file
				string webconfig = File.ReadAllText(Path.Combine(sourcePath, "Generic\\Web.config_"));
				webconfig = webconfig
					.Replace("%SERVICE_FULLNAME%", _compositeNamespace + "." + compositeidentifier)
					.Replace("%SERVICE_NAME%", compositeidentifier)
					.Replace("%INTERFACE_FULLNAME%", _compositeNamespace + ".I" + compositeidentifier)
					.Replace("%NAMESPACE%", _compositeXMLNS);
				File.WriteAllText(Path.Combine(targetPathWCFService, "Web.config"), webconfig);
			}

		}

		private void createWCFServiceCode(
			TypeProvider typeProvider, string targetPathWCFService, ServiceModule composite,
			out CodeCompileUnit ccuService, CodeCompileUnit ccuIService, CodeCompileUnit ccuData,
			out CodeCompileUnit ccuMapping, out CodeCompileUnit ccuContracts, CodeCompileUnit ccuRules, bool generateStub)
		{
			RepositoryService repsvc = composite.GetService(typeof(RepositoryService)) as RepositoryService;
			if ( repsvc == null ) throw new NullReferenceException("RepositoryService not available.");

			ccuMapping = null;
			ccuContracts = null;
			CodeTypeDeclaration ctdMapping = null;

			bool hasOpenCompositeWFExtNamespace = false;
			string compositeidentifier = RepositoryService.GetIdentifier(composite.Name);

			#region Initialize Config File
			string configFile = Path.Combine(targetPathWCFService, "web.config");
			//if ( File.Exists(configFile) ) {
			//    File.Delete(configFile);
			//}
			Configuration machineConfig = ConfigurationManager.OpenMachineConfiguration();
			ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
			fileMap.ExeConfigFilename = configFile;
			fileMap.MachineConfigFilename = machineConfig.FilePath;

			Configuration configuration = ConfigurationManager
				.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
			configuration.NamespaceDeclared = true;
			//configuration.RootSectionGroup.Sections[
			configuration.Save(ConfigurationSaveMode.Minimal, true);
			#endregion

			// create new ccuService
			ccuService = new CodeCompileUnit();

			// initialize ccuService
			// add empty namespace imports
			CodeNamespace nsEmpty = new CodeNamespace();
			nsEmpty.Imports.Add(new CodeNamespaceImport("System"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Diagnostics"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Reflection"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Runtime.Serialization"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.ServiceModel"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Text"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Threading"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Web.Services"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Workflow.Activities"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Workflow.Runtime"));
			nsEmpty.Imports.Add(new CodeNamespaceImport(_compositeDataNamespace));
			ccuService.Namespaces.Add(nsEmpty);

			// add namespace for service
			CodeNamespace nsService = new CodeNamespace(_compositeNamespace);
			ccuService.Namespaces.Add(nsService);

			// create service type
			CodeTypeDeclaration ctdService = new CodeTypeDeclaration(compositeidentifier);
			ctdService.Attributes = MemberAttributes.Public;
			// add base interface
			ctdService.BaseTypes.Add("I" + compositeidentifier);
			// add [ServiceBehavior(
			//		Namespace="http://www.OpenComposite.com/canonical_document",
			//		InstanceContextMode=InstanceContextMode.Single)]
			ctdService.CustomAttributes.Add(
				new CodeAttributeDeclaration(
					new CodeTypeReference(typeof(ServiceBehaviorAttribute)),
					new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(_compositeXMLNS)),
					new CodeAttributeArgument("InstanceContextMode",
						new CodeFieldReferenceExpression(
							new CodeTypeReferenceExpression(typeof(InstanceContextMode)), "Single"))));
			// add service to namespace
			nsService.Types.Add(ctdService);

			// add constructor
			CodeConstructor ctorService = new CodeConstructor();
			ctorService.Attributes = MemberAttributes.Public | MemberAttributes.Final;
			ctdService.Members.Add(ctorService);

			typeProvider.AddCodeCompileUnit(ccuService);

			Deployment deployment = new Deployment(composite);
			// add capability methods to ccuService
			foreach ( Verb verb in composite.GetVerbs() ) {
				// if available: deploy workflow and create workflow start method
				bool isWorkflow = false;
				Operation op = repsvc.GetItem<Operation>(composite.ExtendedProperties.ExposedVerbOperation[verb.ID]);
				if ( op != null && op.WorkflowId > 0 ) {
					// deploy workflow
					isWorkflow = true;
					Repository.Workflow wf = op.GetWorkflow();
					wf.BuildType = composite.ExtendedProperties.BuildType;

					deployment.DeployWorkflow(_targetPath, wf, _update);
					createWFMethods(nsEmpty, ctdService, ctorService, wf, verb);
					if ( !hasOpenCompositeWFExtNamespace ) {
						nsEmpty.Imports.Add(new CodeNamespaceImport("OpenComposite.Workflow.Extensions"));
						hasOpenCompositeWFExtNamespace = true;
					}
				}

				if ( !isWorkflow ) {
					// create method for verb/capability method
					CodeMemberMethod method = new CodeMemberMethod();
					method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
					method.Name = verb.Name;
					if ( !string.IsNullOrEmpty(verb.Description) ) {
						method.Comments.Add(new CodeCommentStatement(verb.Description));
					}
					// if input business object exists: add input parameter
					if ( verb.InputBusinessObjectID > 0 ) {
						string argName = createArgumentName(verb.InputBusinessObjectName);
						method.Parameters.Add(
							new CodeParameterDeclarationExpression(
								_compositeDataNamespace + "." + verb.InputBusinessObjectName,
								argName));
					}
					// if output business object exists: set return type
					if ( verb.OutputBusinessObjectID > 0 ) {
						method.ReturnType = new CodeTypeReference(
							_compositeDataNamespace + "." + verb.OutputBusinessObjectName);
					}
					if ( ccuMapping == null ) {
						ccuMapping = new CodeCompileUnit();
						CodeNamespace nsMapping = new CodeNamespace(this.Namespace);
						nsMapping.Imports.Add(new CodeNamespaceImport("System"));
						nsMapping.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
						nsMapping.Imports.Add(new CodeNamespaceImport("System.Text"));
						ccuMapping.Namespaces.Add(nsMapping);
						ctdMapping = new CodeTypeDeclaration("Mapping");
						ctdMapping.Attributes = MemberAttributes.Public;
						ctdMapping.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(SerializableAttribute))));
						nsMapping.Types.Add(ctdMapping);
						typeProvider.AddCodeCompileUnit(ccuMapping);
					}
					if ( ccuContracts == null ) {
						ccuContracts = new CodeCompileUnit();
						typeProvider.AddCodeCompileUnit(ccuContracts);
					}

					if ( !createProxyMethod(typeProvider, ccuData, configuration, nsEmpty,
											ccuService, ctdService, ctorService,
											ccuMapping, ctdMapping, ccuContracts, ccuRules,
											verb, generateStub) ) {
						// add "Add your code here" comment and throw NotImplementedException
						method.Statements.Add(new CodeCommentStatement("Add your code here"));
						method.Statements.Add(
							new CodeThrowExceptionStatement(
								new CodeObjectCreateExpression(typeof(NotImplementedException))));
						// add method to service
						ctdService.Members.Add(method);
					}
				}
			}
		}

		private void createWCFIServiceAndDataCode(TypeProvider typeProvider, ServiceModule composite,
			out CodeCompileUnit ccuIService, out CodeCompileUnit ccuData,
			out bool hasWorkflow, out List<XmlDocument> configsWF, out List<Repository.Workflow> workflows)
		{
			RepositoryService repsvc = composite.GetService(typeof(RepositoryService)) as RepositoryService;
			if ( repsvc == null ) throw new NullReferenceException("RepositoryService not available.");

			hasWorkflow = false;
			configsWF = new List<XmlDocument>();
			workflows = new List<OpenComposite.EII.Repository.Workflow>();

			string compositeidentifier = RepositoryService.GetIdentifier(composite.Name);
			// create new ccuIService and ccuData
			ccuIService = new CodeCompileUnit();
			ccuData = new CodeCompileUnit();

			// initialize ccuIService
			// add empty namespace imports
			CodeNamespace nsEmpty = new CodeNamespace();
			nsEmpty.Imports.Add(new CodeNamespaceImport("System"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Diagnostics"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Text"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.ServiceModel"));
			nsEmpty.Imports.Add(new CodeNamespaceImport("System.Web.Services"));
			nsEmpty.Imports.Add(new CodeNamespaceImport(_compositeDataNamespace));
			ccuIService.Namespaces.Add(nsEmpty);

			// add namespace for interface
			CodeNamespace nsInterface = new CodeNamespace(_compositeNamespace);
			ccuIService.Namespaces.Add(nsInterface);

			// create interface type
			CodeTypeDeclaration typeInterface = new CodeTypeDeclaration("I" + compositeidentifier);
			typeInterface.IsInterface = true;
			typeInterface.Attributes = MemberAttributes.Public;
			// add custom attributes (ServiceContractAttribute)
			typeInterface.CustomAttributes.Add(
				new CodeAttributeDeclaration(
					new CodeTypeReference(typeof(ServiceContractAttribute)),
					new CodeAttributeArgument("CallbackContract",
						new CodeTypeOfExpression("I" + compositeidentifier + "Callback")),
					new CodeAttributeArgument("Namespace",
						new CodePrimitiveExpression(_compositeXMLNS))));
			// add interface to namespace
			nsInterface.Types.Add(typeInterface);

			// create callback interface type
			CodeTypeDeclaration typeICallback = new CodeTypeDeclaration("I" + compositeidentifier + "Callback");
			typeICallback.IsInterface = true;
			typeICallback.Attributes = MemberAttributes.Public;
			// add custim attributes (ServiceContractAttribute)
			typeICallback.CustomAttributes.Add(
				new CodeAttributeDeclaration(
					new CodeTypeReference(typeof(ServiceContractAttribute)),
					new CodeAttributeArgument("Namespace",
						new CodePrimitiveExpression(_compositeXMLNS))));
			// add callback interface to namespace
			nsInterface.Types.Add(typeICallback);

			// add capability methods to ccuIService and input / output business objects to ccuData
			foreach ( Verb verb in composite.GetVerbs() ) {
				// if verb is assigned to workflow
				bool isWorkflow = false;
				Repository.Workflow workflow = null;
				Operation op = repsvc.GetItem<Operation>(composite.ExtendedProperties.ExposedVerbOperation[verb.ID]);
				if ( op != null && op.WorkflowId > 0 ) {
					// deploy workflow
					isWorkflow = true;
					hasWorkflow = true;
					workflow = op.GetWorkflow();
					XmlDocument xd = new XmlDocument();
					xd.LoadXml(workflow.ExtendedProperties.ConfigurationString);
					configsWF.Add(xd);
					workflows.Add(workflow);
				}

				// if exists: add input business object to ccuData
				if ( verb.InputBusinessObjectID > 0 ) {
					addBusinessObjectToDataCode(ccuData, verb.InputBusinessObject, true);
				}
				// if exists: add output business object to ccuData
				if ( verb.OutputBusinessObjectID > 0 ) {
					addBusinessObjectToDataCode(ccuData, verb.OutputBusinessObject, true);
				}
				// create method for verb/capability method
				CodeMemberMethod method = new CodeMemberMethod();
				method.Attributes = 0;
				method.Name = verb.Name;
				if ( !string.IsNullOrEmpty(verb.Description) ) {
					method.Comments.Add(new CodeCommentStatement(verb.Description));
				}
				// if input business object exists: add input parameter
				if ( verb.InputBusinessObjectID > 0 ) {
					if ( isWorkflow ) {
						method.Parameters.Add(
							new CodeParameterDeclarationExpression(
								workflow.ExtendedProperties.NamespaceCode + ".Data." + verb.InputBusinessObjectName,
								createArgumentName(verb.InputBusinessObjectName)));
					} else {
						method.Parameters.Add(
							new CodeParameterDeclarationExpression(
								_compositeDataNamespace + "." + verb.InputBusinessObjectName,
								createArgumentName(verb.InputBusinessObjectName)));
					}
				}
				// if output business object exists: set return type
				if ( verb.OutputBusinessObjectID > 0 ) {
					if ( isWorkflow ) {
						// create callback method
						CodeMemberMethod callbackMethod = new CodeMemberMethod();
						callbackMethod.Attributes = 0;
						callbackMethod.Name = verb.Name + "Callback";
						// add parameter
						callbackMethod.Parameters.Add(
							new CodeParameterDeclarationExpression(
								workflow.ExtendedProperties.NamespaceCode + ".Data." + verb.OutputBusinessObjectName,
								createArgumentName(verb.OutputBusinessObjectName)));
						// add custom attributes (OperationContractAttribute)
						callbackMethod.CustomAttributes.Add(
							new CodeAttributeDeclaration(
								new CodeTypeReference(typeof(OperationContractAttribute)),
								new CodeAttributeArgument("IsOneWay", new CodePrimitiveExpression(true))));
						// add callback method to callback interface
						typeICallback.Members.Add(callbackMethod);
					} else {
						method.ReturnType = new CodeTypeReference(
							_compositeDataNamespace + "." + verb.OutputBusinessObjectName);
					}
				}
				// add custom attributes (OperationContractAttribute)
				if ( isWorkflow ) {
					method.CustomAttributes.Add(
						new CodeAttributeDeclaration(
							new CodeTypeReference(typeof(OperationContractAttribute)),
							new CodeAttributeArgument("IsOneWay", new CodePrimitiveExpression(true))));
				} else {
					method.CustomAttributes.Add(
						new CodeAttributeDeclaration(
							new CodeTypeReference(typeof(OperationContractAttribute))));
				}
				// add method to interface
				typeInterface.Members.Add(method);
			}

			typeProvider.AddCodeCompileUnit(ccuIService);
			typeProvider.AddCodeCompileUnit(ccuData);
		}

		private void createSolutionFile(ServiceModule composite, List<Repository.Workflow> workflows)
		{
			string sln = cSolutionBase;
			string projects = "";
			string builds = "";
			string wsrefs = "";

			foreach ( Repository.Workflow wf in workflows ) {
				string guidPrj = Guid.NewGuid().ToString("B").ToUpper();
				string wfpath = wf.Path;
				string csprjpath = Path.Combine(wfpath, wf.Name + ".csproj");

				// set project guid in csproj file
				XmlDocument csproj = new XmlDocument();
				csproj.Load(csprjpath);
				XmlNamespaceManager nsmgr = new XmlNamespaceManager(csproj.NameTable);
				nsmgr.AddNamespace("tns", "http://schemas.microsoft.com/developer/msbuild/2003");
				XmlNode xnPrjGuid = csproj.SelectSingleNode("//tns:PropertyGroup/tns:ProjectGuid", nsmgr);
				xnPrjGuid.InnerText = guidPrj;
				csproj.Save(csprjpath);
				// set project for solution file
				string relpath = csprjpath.Replace(_targetPath, "");
				if ( relpath.StartsWith("\\") ) relpath = relpath.Substring(1, relpath.Length - 1);
				projects += string.Format(cSolutionProject, wf.Name, relpath, guidPrj);
				// set builds for solution
				builds += string.Format(cSolutionPrjBuildConfig, guidPrj);
				// set webservice project references
				wsrefs += string.Format("{0}|{1}.dll;", guidPrj, wf.Name);
			}
			string guidWSProj = Guid.NewGuid().ToString("B").ToUpper();
			// add web service project
			projects += string.Format(cSolutionWebService, guidWSProj, wsrefs);
			// add web service builds
			builds += string.Format(cSolutionPrjBuildConfig, guidWSProj);

			sln = string.Format(sln, projects, builds);

			File.WriteAllText(Path.Combine(_targetPath, composite.Name + ".sln"), sln);
		}

		private string createArgumentName(string baseName)
		{
			StringBuilder b = new StringBuilder(baseName.Length);
			for ( int i = 0; i < baseName.Length; i++ ) {
				if ( Char.IsUpper(baseName[i]) && ( i == 0 || i == baseName.Length - 1 || Char.IsUpper(baseName[i + 1]) ) ) {
					b.Append(Char.ToLower(baseName[i]));
				} else {
					b.Append(baseName.Substring(i));
					break;
				}
			}
			return b.ToString();
		}

		private void addBusinessObjectToDataCode(CodeCompileUnit ccuData, BusinessObject businessObject,
												 bool generateDataContract)
		{
			if ( businessObject == null ) {
				throw new ArgumentNullException("businessObject");
			}
			if ( businessObject.Schema == null ) {
				throw new NullReferenceException(
					string.Format("The business object \"{0}\" contains no schema.", businessObject.Name));
			}
			try {
				XmlSchemaSet xsdset = createXmlSchemaSetForDataContract();
				xsdset.Add(businessObject.Schema);
				// compile schema
				xsdset.Compile();
				if ( generateDataContract ) {
					addDataContractsToDataCode(xsdset, ccuData, businessObject);
				} else {
					addXmlClassesToDataCode(xsdset, ccuData, businessObject);
				}
			} catch ( Exception ex ) {
				throw new Exception(
					string.Format("Error in Business Object \"{0}\".{1}{1}{2}",
								  businessObject.Name, Environment.NewLine, ex.Message),
					ex);
			}
			// refresh typeProvider
			//refreshTypeProvider(ref typeProvider, ref _codeData);
		}
		private void addDataContractsToDataCode(XmlSchemaSet xsdset, CodeCompileUnit ccuData, BusinessObject bobject)
		{
			XsdDataContractImporter importer = new XsdDataContractImporter();
			importer.Options = new ImportOptions();
			importer.Options.Namespaces.Add("*", _compositeDataNamespace);
			importer.Options.GenerateSerializable = true;
			//importer.Options.DataContractSurrogate
			importer.Import(xsdset);

			foreach ( CodeNamespace newNamespace in importer.CodeCompileUnit.Namespaces ) {
				foreach ( CodeTypeDeclaration newType in newNamespace.Types ) {
					bool bTypeExists = false;
					CodeNamespace targetNamespace = null;
					foreach ( CodeNamespace dataNamespace in ccuData.Namespaces ) {
						if ( dataNamespace.Name == newNamespace.Name ) {
							targetNamespace = dataNamespace;
							break;
						}
					}
					if ( targetNamespace != null ) {
						foreach ( CodeTypeDeclaration dataType in targetNamespace.Types ) {
							if ( dataType.Name == newType.Name ) {
								bTypeExists = true;
								break;
							}
						}
					}
					if ( !bTypeExists ) {
						if ( targetNamespace != null ) {
							targetNamespace.Types.Add(newType);
						} else {
							ccuData.Namespaces.Add(newNamespace);
						}
						#region add RepositoryInformationAttribute to business object classes
						foreach ( CodeTypeMember member in newType.Members ) {
							if ( (int)member.Attributes == 20482 ) {
								foreach ( BusinessObjectField field in bobject.BusinessObjectFields ) {
									if ( field.BusinessObject == null ) continue;
									if ( field.BusinessObject.Name == member.Name ||
										string.Format("{0}Type", field.BusinessObject) == member.Name ) {
										member.CustomAttributes.Add(new CodeAttributeDeclaration(
											new CodeTypeReference(typeof(RepositoryInformationAttribute)),
												new CodeAttributeArgument(
													new CodePrimitiveExpression(field.BusinessObject.ID)),
												new CodeAttributeArgument(
													new CodePrimitiveExpression(field.BusinessObject.Name)),
												new CodeAttributeArgument(
													new CodePrimitiveExpression(field.BusinessObject.RepositoryItemTypeName))));
									}
									break;
								}
							}
						}
						BusinessObject bo = bobject;
						if ( bo.Name != newType.Name ) {
							foreach ( BusinessObjectField field in bo.BusinessObjectFields ) {
								if ( field.BusinessObject == null ) continue;
								if ( field.BusinessObject.Name == newType.Name ) {
									bo = field.BusinessObject;
									break;
								}
							}
						}
						newType.CustomAttributes.Add(
							new CodeAttributeDeclaration(
								new CodeTypeReference(typeof(RepositoryInformationAttribute)),
									new CodeAttributeArgument(
										new CodePrimitiveExpression(bo.ID)),
									new CodeAttributeArgument(
										new CodePrimitiveExpression(bo.Name)),
									new CodeAttributeArgument(
										new CodePrimitiveExpression(bo.RepositoryItemTypeName))));
						#endregion
					}
				}
			}
		}
		/// <summary>
		/// Add xml serializable classes to data CodeCompileUnit.
		/// </summary>
		/// <param name="xsdset"></param>
		/// <param name="ccuData"></param>
		/// <returns></returns>
		private void addXmlClassesToDataCode(XmlSchemaSet xsdset, CodeCompileUnit ccuData, BusinessObject bobject)
		{
			XmlSchemas xsds = new XmlSchemas();
			foreach ( XmlSchema xsd in xsdset.Schemas() ) {
				xsds.Add(xsd);
			}
			xsds.Compile(null, true);
			XmlSchemaImporter schemaImporter = new XmlSchemaImporter(xsds);

			CodeNamespace codeNSNew = new CodeNamespace(_compositeDataNamespace);
			XmlCodeExporter codeExporter = new XmlCodeExporter(codeNSNew);
			List<XmlTypeMapping> maps = new List<XmlTypeMapping>();

			foreach ( XmlSchema xsd in xsds ) {
				foreach ( XmlSchemaType schemaType in xsd.SchemaTypes.Values ) {
					maps.Add(schemaImporter.ImportSchemaType(schemaType.QualifiedName));
				}
				foreach ( XmlSchemaElement schemaElement in xsd.Elements.Values ) {
					maps.Add(schemaImporter.ImportTypeMapping(schemaElement.QualifiedName));
				}
			}
			foreach ( XmlTypeMapping map in maps ) {
				codeExporter.ExportTypeMapping(map);
			}

			// create the codedom
			CodeNamespace codeNamespace = null;
			foreach ( CodeNamespace codens in ccuData.Namespaces ) {
				if ( codens.Name == _compositeDataNamespace ) {
					codeNamespace = codens;
					break;
				}
			}
			if ( codeNamespace == null ) {
				codeNamespace = new CodeNamespace(_compositeDataNamespace);
				ccuData.Namespaces.Add(codeNamespace);
			}
			foreach ( CodeTypeDeclaration typeNew in codeNSNew.Types ) {
				bool bFound = false;
				foreach ( CodeTypeDeclaration type in codeNamespace.Types ) {
					if ( type.Name == typeNew.Name ) {
						bFound = true;
						break;
					}
				}
				if ( !bFound ) {
					codeNamespace.Types.Add(typeNew);
					#region add RepositoryInformationAttribute to business object classes
					foreach ( CodeTypeMember member in typeNew.Members ) {
						if ( (int)member.Attributes == 20482 ) {
							foreach ( BusinessObjectField field in bobject.BusinessObjectFields ) {
								if ( field.BusinessObject == null ) continue;
								if ( field.BusinessObject.Name == member.Name ||
									string.Format("{0}Type", field.BusinessObject) == member.Name ) {
									member.CustomAttributes.Add(new CodeAttributeDeclaration(
										new CodeTypeReference(typeof(RepositoryInformationAttribute)),
											new CodeAttributeArgument(
												new CodePrimitiveExpression(field.BusinessObject.ID)),
											new CodeAttributeArgument(
												new CodePrimitiveExpression(field.BusinessObject.Name)),
											new CodeAttributeArgument(
												new CodePrimitiveExpression(field.BusinessObject.RepositoryItemTypeName))));
								}
								break;
							}
						}
					}
					BusinessObject bo = bobject;
					if ( bo.Name != typeNew.Name ) {
						foreach ( BusinessObjectField field in bo.BusinessObjectFields ) {
							if ( field.BusinessObject == null ) continue;
							if ( field.BusinessObject.Name == typeNew.Name ) {
								bo = field.BusinessObject;
								break;
							}
						}
					}
					typeNew.CustomAttributes.Add(
						new CodeAttributeDeclaration(
							new CodeTypeReference(typeof(RepositoryInformationAttribute)),
								new CodeAttributeArgument(
									new CodePrimitiveExpression(bo.ID)),
								new CodeAttributeArgument(
									new CodePrimitiveExpression(bo.Name)),
								new CodeAttributeArgument(
									new CodePrimitiveExpression(bo.RepositoryItemTypeName))));
					#endregion
				}
			}
		}
		private XmlSchemaSet createXmlSchemaSetForDataContract()
		{
			XsdDataContractExporter ex = new XsdDataContractExporter();
			ex.Export(typeof(OpenComposite.EII.Designer.Workflow.Help));
			XmlSchemaSet xsdset = ex.Schemas;
			XmlSchema xsdRemove = null;
			foreach ( XmlSchema xsd in xsdset.Schemas() ) {
				if ( xsd.Elements.Contains(new XmlQualifiedName("Help", xsd.TargetNamespace)) ) {
					xsdRemove = xsd;
				}
			}
			xsdset.Remove(xsdRemove);
			return xsdset;
		}

		private void createWFMethods(CodeNamespace codeNamespaceEmpty, CodeTypeDeclaration codeService,
			CodeConstructor ctorService, Repository.Workflow workflow, Verb verb)
		{
			string proxyTypeName = workflow.Name + "Proxy";
			string proxyVarName = "_" + workflow.Name + "Proxy";
			string callbackTypeName = "I" + workflow.Name + "Callback";
			string callbackClientsVarName = "_" + workflow.Name + "Clients";
			string methNameSetupWFEnv = cSetupWFEnvironment + workflow.Name;
			// add orchestration namespace to usings
			codeNamespaceEmpty.Imports.Add(new CodeNamespaceImport(workflow.ExtendedProperties.NamespaceCode));
			// create class variables
			// _workflowRuntime
			if ( _wfRuntime == null ) {
				_wfRuntime = new CodeMemberField(typeof(WorkflowRuntime), cWorkflowRuntime);
				codeService.Members.Add(_wfRuntime);
			}
			// _workflowProxy
			codeService.Members.Add(new CodeMemberField(proxyTypeName, proxyVarName));
			// _workflowClients
			CodeTypeReference typeRefDicGuidCallback = new CodeTypeReference(
				typeof(System.Collections.Generic.Dictionary<,>));
			typeRefDicGuidCallback.TypeArguments.Add(typeof(Guid));
			typeRefDicGuidCallback.TypeArguments.Add(callbackTypeName);
			CodeMemberField fieldCallbackClients = new CodeMemberField();
			fieldCallbackClients.Name = callbackClientsVarName;
			fieldCallbackClients.Type = typeRefDicGuidCallback;
			codeService.Members.Add(fieldCallbackClients);
			// add initialization to ctor
			ctorService.Statements.Add(
				new CodeAssignStatement(
					new CodeFieldReferenceExpression(
						new CodeThisReferenceExpression(), callbackClientsVarName),
					new CodeObjectCreateExpression(typeRefDicGuidCallback)));
			//public void CapMethod4c(OpenComposite.Orchestration.orch7.Data.item input) {
			string inputArgName = createArgumentName(verb.InputBusinessObjectName);
			CodeMemberMethod methodStartWF = new CodeMemberMethod();
			methodStartWF.Attributes = MemberAttributes.Public | MemberAttributes.Final;
			methodStartWF.Name = workflow.StartName;
			methodStartWF.Parameters.Add(
				new CodeParameterDeclarationExpression(
					workflow.ExtendedProperties.NamespaceCode + ".Data." + verb.InputBusinessObjectName,
					inputArgName));

			//    setupWFEnvironment();
			methodStartWF.Statements.Add(
				new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), methNameSetupWFEnv));

			//    Assembly asm = Assembly.Load("orch7");
			methodStartWF.Statements.Add(
				new CodeVariableDeclarationStatement(
					typeof(Assembly), "asm",
					new CodeMethodInvokeExpression(
						new CodeTypeReferenceExpression(typeof(Assembly)), "Load",
						new CodePrimitiveExpression(workflow.Name))));
			//    Type workflowType = asm.GetType("OpenComposite.Orchestration.orch7.orch7");
			methodStartWF.Statements.Add(
				new CodeVariableDeclarationStatement(
					typeof(Type), "workflowType",
					new CodeMethodInvokeExpression(
						new CodeVariableReferenceExpression("asm"), "GetType",
						new CodePrimitiveExpression(workflow.ExtendedProperties.FullName))));

			//    WorkflowInstance workflowInstance = _workflowRuntime.CreateWorkflow(workflowType);
			methodStartWF.Statements.Add(
				new CodeVariableDeclarationStatement(
					typeof(WorkflowInstance), "workflowInstance",
					new CodeMethodInvokeExpression(
						new CodeFieldReferenceExpression(
							new CodeThisReferenceExpression(), cWorkflowRuntime),
						"CreateWorkflow",
						new CodeVariableReferenceExpression("workflowType"))));
			//    workflowInstance.Start();
			methodStartWF.Statements.Add(
				new CodeMethodInvokeExpression(
					new CodeVariableReferenceExpression("workflowInstance"), "Start"));
			//    Iorch7Callback caller = OperationContext.Current.GetCallbackChannel<Iorch7Callback>();
			methodStartWF.Statements.Add(
				new CodeVariableDeclarationStatement(
					callbackTypeName, "caller",
					new CodeMethodInvokeExpression(
						new CodeMethodReferenceExpression(
							new CodePropertyReferenceExpression(
								new CodeTypeReferenceExpression(typeof(OperationContext)),
								"Current"),
							"GetCallbackChannel",
							new CodeTypeReference(callbackTypeName)))));
			//    if ( caller != null && !_clients.ContainsKey(workflowInstance.InstanceId) ) {
			methodStartWF.Statements.Add(
				new CodeConditionStatement(
					new CodeBinaryOperatorExpression(
						new CodeBinaryOperatorExpression(
							new CodeVariableReferenceExpression("caller"),
							CodeBinaryOperatorType.IdentityInequality,
							new CodePrimitiveExpression(null)),
						CodeBinaryOperatorType.BooleanAnd,
						new CodeBinaryOperatorExpression(
							new CodeMethodInvokeExpression(
								new CodeFieldReferenceExpression(
									new CodeThisReferenceExpression(), callbackClientsVarName),
								"ContainsKey",
								new CodePropertyReferenceExpression(
									new CodeVariableReferenceExpression("workflowInstance"), "InstanceId")),
							CodeBinaryOperatorType.ValueEquality,
							new CodePrimitiveExpression(false))),
				//        _clients.Add(workflowInstance.InstanceId, caller);
					new CodeExpressionStatement(new CodeMethodInvokeExpression(
						new CodeFieldReferenceExpression(
							new CodeThisReferenceExpression(), callbackClientsVarName),
						"Add",
						new CodePropertyReferenceExpression(
							new CodeVariableReferenceExpression("workflowInstance"), "InstanceId"),
						new CodeVariableReferenceExpression("caller")))));
			//    }
			//	  _localService.test_ReplyEvent += new test_ReplyEventHandler(workflow_ReplyEvent);

			//    _localService.RaiseCapMethod4cEvent(workflowInstance.InstanceId, input);
			methodStartWF.Statements.Add(
				new CodeMethodInvokeExpression(
					new CodeFieldReferenceExpression(
						new CodeThisReferenceExpression(), proxyVarName),
					"Raise" + workflow.ExtendedProperties.StartMethodName + "Event",
					new CodePropertyReferenceExpression(
						new CodeVariableReferenceExpression("workflowInstance"), "InstanceId"),
					new CodeArgumentReferenceExpression(inputArgName)));
			//}
			codeService.Members.Add(methodStartWF);

			//private void setupWFEnvironment() {
			CodeMemberMethod methodSetupWF = new CodeMemberMethod();
			methodSetupWF.Attributes = MemberAttributes.Private | MemberAttributes.Final;
			methodSetupWF.Name = methNameSetupWFEnv;
			// if ( _localService == null ) {
			CodeConditionStatement codeIfLSEqNull = new CodeConditionStatement();
			codeIfLSEqNull.Condition =
				new CodeBinaryOperatorExpression(
					new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), proxyVarName),
					CodeBinaryOperatorType.ValueEquality,
					new CodePrimitiveExpression(null));
			//  WfWcfExtension extension = OperationContext.Current.Host.Extensions.Find<WfWcfExtension>();
			codeIfLSEqNull.TrueStatements.Add(
				new CodeVariableDeclarationStatement(
					typeof(OpenComposite.Workflow.Extensions.WfWcfExtension), "extension",
					new CodeMethodInvokeExpression(
						new CodeMethodReferenceExpression(
							new CodePropertyReferenceExpression(
								new CodePropertyReferenceExpression(
									new CodePropertyReferenceExpression(
										new CodeTypeReferenceExpression(typeof(OperationContext)),
										"Current"),
									"Host"),
								"Extensions"),
							"Find",
							new CodeTypeReference(typeof(OpenComposite.Workflow.Extensions.WfWcfExtension))))));
			//  _workflowRuntime = extension.WorkflowRuntime;
			codeIfLSEqNull.TrueStatements.Add(
				new CodeAssignStatement(
					new CodeFieldReferenceExpression(
						new CodeThisReferenceExpression(), cWorkflowRuntime),
					new CodePropertyReferenceExpression(
						new CodeVariableReferenceExpression("extension"),
						"WorkflowRuntime")));
			//  ExternalDataExchangeService dataExchangeSvc = _workflowRuntime.GetService<ExternalDataExchangeService>();
			codeIfLSEqNull.TrueStatements.Add(
				new CodeVariableDeclarationStatement(
					typeof(ExternalDataExchangeService),
					"dataExchangeSvc",
					new CodeMethodInvokeExpression(
						new CodeMethodReferenceExpression(
							new CodeFieldReferenceExpression(
								new CodeThisReferenceExpression(), cWorkflowRuntime),
							"GetService",
							new CodeTypeReference(typeof(ExternalDataExchangeService))))));
			//  _localService = (orch7Proxy)dataExchangeSvc.GetService(typeof(orch7Proxy));
			codeIfLSEqNull.TrueStatements.Add(
				new CodeAssignStatement(
					new CodeFieldReferenceExpression(
						new CodeThisReferenceExpression(), proxyVarName),
					new CodeCastExpression(
						proxyTypeName,
						new CodeMethodInvokeExpression(
							new CodeVariableReferenceExpression("dataExchangeSvc"),
							"GetService",
							new CodeTypeOfExpression(proxyTypeName)))));
			//  if ( _localService == null ) {
			codeIfLSEqNull.TrueStatements.Add(
				new CodeConditionStatement(
					new CodeBinaryOperatorExpression(
						new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), proxyVarName),
						CodeBinaryOperatorType.ValueEquality,
						new CodePrimitiveExpression(null)),
				// _localService = new orch7Proxy(_workflowRuntime);
					new CodeAssignStatement(
						new CodeFieldReferenceExpression(
							new CodeThisReferenceExpression(), proxyVarName),
						new CodeObjectCreateExpression(
							proxyTypeName,
							new CodeFieldReferenceExpression(
								new CodeThisReferenceExpression(), cWorkflowRuntime))),
				// dataExchangeSvc.AddService(_localService);
					new CodeExpressionStatement(
						new CodeMethodInvokeExpression(
							new CodeVariableReferenceExpression("dataExchangeSvc"),
							"AddService",
							new CodeFieldReferenceExpression(
								new CodeThisReferenceExpression(), proxyVarName)))));
			//  }
			if ( verb.OutputBusinessObjectID > 0 ) {
				codeIfLSEqNull.TrueStatements.Add(
					new CodeAttachEventStatement(
						new CodeEventReferenceExpression(
							new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), proxyVarName),
							verb.Name + "_ReplyEvent"),
						new CodeDelegateCreateExpression(
							new CodeTypeReference(verb.Name + "_ReplyEventHandler"),
							new CodeThisReferenceExpression(),
							workflow.Name + "_ReplyEvent")));
			}
			// }
			//}
			methodSetupWF.Statements.Add(codeIfLSEqNull);
			codeService.Members.Add(methodSetupWF);
			CodeRegionDirective regionS = new CodeRegionDirective(
				CodeRegionMode.Start, workflow.Name + " - Private Members");
			CodeRegionDirective regionE = new CodeRegionDirective(
				CodeRegionMode.End, workflow.Name + " - Private Members");
			methodSetupWF.StartDirectives.Add(regionS);
			if ( verb.OutputBusinessObjectID > 0 ) {
				// add Reply Event Handler
				CodeMemberMethod methodReplyEH = new CodeMemberMethod();
				methodReplyEH.Attributes = MemberAttributes.Private | MemberAttributes.Final;
				methodReplyEH.Name = workflow.Name + "_ReplyEvent";
				methodReplyEH.Parameters.Add(
					new CodeParameterDeclarationExpression(typeof(object), "sender"));
				methodReplyEH.Parameters.Add(
					new CodeParameterDeclarationExpression(verb.Name + "_ReplyEventArgs", "e"));

				string snippet = CompositeDeployment.CodeMethodworkflow_ReplyEvent;
				string methodcallbackcall = "";
				//callback.%WF_STARTMETHODNAME%Callback(e.Output);
				if ( string.IsNullOrEmpty(workflow.ExtendedProperties.OutputType) ) {
					methodcallbackcall = string.Format(
						"callback.{0}Callback();", workflow.ExtendedProperties.StartMethodName);
				} else {
					methodcallbackcall = string.Format(
						"callback.{0}Callback(e.Output);", workflow.ExtendedProperties.StartMethodName);
				}
				snippet = snippet
					.Replace("%WF_NAME%", workflow.Name)
					.Replace("%DICT_CLIENTS%", callbackClientsVarName)
					.Replace("%WF_METHODCALLBACK_CALL%", methodcallbackcall);

				methodReplyEH.Statements.Add(new CodeSnippetStatement(snippet));
				methodReplyEH.EndDirectives.Add(regionE);
				codeService.Members.Add(methodReplyEH);
			} else {
				methodSetupWF.EndDirectives.Add(regionE);
			}
		}

		private bool createProxyMethod(TypeProvider typeProvider,
			CodeCompileUnit ccuData, Configuration configuration,
			CodeNamespace codeNamespaceEmpty,
			CodeCompileUnit ccuService, CodeTypeDeclaration ctdService, CodeConstructor ctorService,
			CodeCompileUnit ccuMapping, CodeTypeDeclaration ctdMapping, CodeCompileUnit ccuContracts,
			CodeCompileUnit ccuRules,
			Verb verb, bool generateStub)
		{
			Deployment deployment = new Deployment(_composite);

			bool isHumanActivity = false;
			string endpointConfigName = null;
			ServiceGenerationType currentSvcGenType = ServiceGenerationType.Unknown;

			//XmlSchemaSet xsdset;
			CodeTypeReference typeRefLogActContract = null;

			// get logical method
			Repository.LogicalWebMethod logwmeth = verb.DefaultLogicalMethod;
			// webservice/method
			Repository.WebMethod webmeth = null;
			Repository.WebMethod webmethCallback = null;
			Repository.WebService websvc = null;
			// human activity
			Repository.HumanActivity hact = null;

			#region initialize webservice, webmethod and human activity
			if ( logwmeth != null ) {
				websvc = logwmeth.GetAssignedWebService();
				webmeth = logwmeth.GetAssignedWebMethod();
				webmethCallback = logwmeth.GetCallbackWebMethod();
				hact = logwmeth.GetAssignedHumanActivity();//logact.GetHumanActivity();
			} else {
				return false;
			}

			// if not assigned to a web method: return false
			if ( webmeth == null ) return false;

			// create process_activity for HumanComponent
			if ( hact != null ) {
				return false;
				//websvc = hact.WebService;
				//if ( websvc != null )
				//    addHumanActivity(logact, websvc.Uri);
				//isHumanActivity = true;
			}

			currentSvcGenType = ServiceGenerationType.Unknown;
			if ( websvc != null ) {
				// set current ServiceGenerationType
				if ( websvc.Type == WebService.ServiceType.APIService ) {
					currentSvcGenType = ServiceGenerationType.APIService;
				} else if ( isHumanActivity ) {
					currentSvcGenType = ServiceGenerationType.HumanActivityService;
				} else if ( websvc.Uri.ToLower().EndsWith(".asmx") ) {
					currentSvcGenType = ServiceGenerationType.SystemWebService;
				} else if ( websvc.Uri.ToLower().EndsWith(".svc") ) {
					currentSvcGenType = ServiceGenerationType.WCFService;
				} else {
					currentSvcGenType = ServiceGenerationType.Unknown;
				}
				// get result web method
				if ( currentSvcGenType == ServiceGenerationType.HumanActivityService ) {
					BindingListEx<Repository.WebMethod> lstWMResult =
						Global.Data.GetRepositoryHierarchyChildRepositoryList<Repository.WebMethod>(
							OpenComposite.EII.Repository.ItemType.WebService, websvc.ID, OpenComposite.EII.Repository.ItemType.WebMethod);
					if ( lstWMResult != null && lstWMResult.Count > 0 ) {
						foreach ( Repository.WebMethod wm in lstWMResult ) {
							if ( wm.Name == "DoHumanActivity" ) {
								webmeth = wm;
							} else if ( wm.Name == "HumanResponse" ) {
								webmethCallback = wm;
							}
						}
					}
				}
			}
			#endregion

			#region generate Data classes
			///////////////////////////
			if ( logwmeth != null ) {
				if ( logwmeth.InputBusinessObject != null && logwmeth.InputBusinessObject.Schema != null )
					deployment.AddSchemaClassesToDataCode(ccuData, _compositeDataNamespace, typeProvider, logwmeth.InputBusinessObject.Schema, logwmeth.InputBusinessObject);
				if ( logwmeth.OutputBusinessObject != null && logwmeth.OutputBusinessObject.Schema != null )
					deployment.AddSchemaClassesToDataCode(ccuData, _compositeDataNamespace, typeProvider, logwmeth.OutputBusinessObject.Schema, logwmeth.OutputBusinessObject);
			}
			///////////////////////////
			#endregion generate Data classes

			#region get generated type of input/output business objects
			///////////////////////////
			CodeTypeReference typeRefOutput = null;
			CodeTypeReference typeRefInput = null;
			List<CodeTypeReference> listTypeRefInputLogAct = new List<CodeTypeReference>();
			if ( logwmeth.InputBusinessObjectID > 0 ) {
				typeRefInput = new CodeTypeReference(this.NamespaceData + "." + logwmeth.InputBusinessObject.Name);
			}
			if ( logwmeth.OutputBusinessObjectID > 0 ) {
				typeRefOutput = new CodeTypeReference(this.NamespaceData + "." + logwmeth.OutputBusinessObject.Name);
			}
			//getGeneratedIOTypesOfLogicalActivity(null, logact, out typeRefOutput, out typeRefInput);
			//getGeneratedIOTypesOfLogicalActivity(null, logact, out typeRefOutput, ref listTypeRefInputLogAct);
			///////////////////////////
			#endregion get generated type of output business object

			#region generate Web Method Contract
			string contractnspace = "Contract";
			System.Web.Services.Description.ServiceDescription wsdl = null;
			Collection<System.ServiceModel.Channels.Binding> bindings = null;
			///////////////////////////
			if ( webmeth != null && websvc != null ) {
				deployment.GenerateWebMethodContract(currentSvcGenType, ref typeProvider,
					ref typeRefLogActContract, websvc,
					ref contractnspace, ref wsdl, ref bindings, null,
					out endpointConfigName, configuration, ccuContracts);
			}
			///////////////////////////
			#endregion generate Web Method Contract

			#region generate Mapping class code
			///////////////////////////
			CodeMemberMethod methInMap = null;
			//CodeMemberMethod methInMapPhys = null;
			CodeMemberMethod methOutMap = null;
			CodeMemberMethod methContract = null;
			CodeTypeReference typeRefMapClass = new CodeTypeReference(_compositeNamespace + ".Mapping");
			if ( webmeth != null && websvc != null ) {
				deployment.GenerateMapping(
					ccuContracts, ccuMapping, ctdMapping, null, null,
					currentSvcGenType, ref typeProvider, typeRefLogActContract,
					logwmeth.Name, null, logwmeth, null, webmeth, webmethCallback, null, ref methInMap, ref methOutMap,
					ref methContract, typeRefMapClass, typeRefOutput, typeRefInput,
					listTypeRefInputLogAct, false, false, false);
			}

			///////////////////////////
			#endregion generate Mapping class code

			#region generate ServiceCalls class code
			///////////////////////////
			//if ( webmeth != null && websvc != null && !generateStub ) {
			deployment.GenerateServiceCalls(
				ccuService, ctdService, ccuContracts, ccuRules,
				currentSvcGenType, typeProvider,
				typeRefLogActContract, verb.Name, false,
				webmeth, webmethCallback, websvc, null, null, null, null,
				contractnspace, methInMap, methOutMap, methContract, typeRefMapClass,
				typeRefOutput, typeRefInput, listTypeRefInputLogAct, bindings,
				endpointConfigName, _compositeDataNamespace, null,
				true, generateStub);
			//}
			///////////////////////////
			#endregion generate ServiceCalls class code

			return true;
		}

		private TypeProvider createTypeProvider(IServiceProvider serviceProvider)
		{
			TypeProvider typeProvider = new TypeProvider(serviceProvider);

			typeProvider.AddAssemblyReference(typeof(System.EventHandler).Assembly.Location);
			typeProvider.AddAssemblyReference(typeof(System.ComponentModel.AttributeCollection).Assembly.Location);
			typeProvider.AddAssemblyReference(typeof(System.Workflow.ComponentModel.CompositeActivity).Assembly.Location);
			typeProvider.AddAssemblyReference(typeof(System.Workflow.Activities.SequentialWorkflowActivity).Assembly.Location);
			typeProvider.AddAssemblyReference(typeof(System.Runtime.Serialization.XsdDataContractImporter).Assembly.Location);
			typeProvider.AddAssemblyReference(typeof(System.ServiceModel.EndpointAddress).Assembly.Location);
			typeProvider.AddAssemblyReference(typeof(System.Web.Services.WebService).Assembly.Location);
			typeProvider.AddAssemblyReference(typeof(System.Xml.XmlDocument).Assembly.Location);
			typeProvider.AddAssemblyReference(typeof(OpenComposite.Base.Structures.RepositoryInformationAttribute).Assembly.Location);
			typeProvider.AddAssemblyReference(typeof(OpenComposite.Workflow.LogicalEPActivity).Assembly.Location);

			return typeProvider;
		}
		#endregion

		#endregion

		#region Internal Enum: DeployType
		internal enum DeployType
		{
			ASPNET,
			WCF
		}
		#endregion
	}
}
